<template>
  <div
    class="tabs-cont"
    ref="tabsCont"
    :style="{width: width, height: height}"
    @touchstart="tchStart($event)"
  >
    <div class="tabs-cont-wrap" ref="tabsContWrap">
      <div
        class="tabs-cont-list"
        v-for="(data, index) in tabs"
        :style="{width: width, height: height}"
        :key="'tabs-cont-list-'+index"
      >
        <!--<div>{{index}}</div>-->
        <!--<slot v-if="Math.abs(tabIndex-index) <= 4" :data="data" :index="index" v-cloak></slot>-->
        <!--<slot v-if="show_list[index]" :data="data" :index="index"></slot>-->
        <slot :data="data" :index="index"></slot>
      </div>
    </div>
  </div>
</template>
<script>
  export default {
    name: 'tabs-cont',
    props: {
      tabs: {
        type: Array,
        default: [],
        required: true
      },
      tabIndex: {
        type: Number,
        default: 0,
        required: true
      },
      width: {
        type: String,
        required: true
      },
      height: {
        type: String,
        required: true
      },

      overflow: { // overflow-y 是否允许滚动
        type: String,
        default: 'auto'
      },
    },
    model: {
      prop: 'tabIndex',
      event: 'tabIndex'
    },
    watch: {
      tabIndex: function (val) {
        this.setWrapLeft(val)
        // this.setShow(this.tabIndex, 0)
      },
      width: function (val, old) {
        this.width_px = this.clientPX(this.width) // 获取真实px
      }
    },
    data() {
      return {
        left: 0,
        width_px: 0,
        enable_scroll: true, // 阻止重复触发切换

        show_list: [], // 控制哪些模块显示，优化动画效果,
        cIndex_time: 375 // 控制 tabIndex +- 2 模块定时隐藏，与列表过渡动画错开
      }
    },
    created() {
      this.tabs.forEach((k, i) => {
        this.show_list[i] = false
      })
      // this.setShow(this.tabIndex, 0)
    },
    mounted() {
      this.width_px = this.clientPX(this.width) // 获取真实px

      this.$nextTick(() => {
        setTimeout(() => {
          this.setWrapLeft()
          this.resetContCss()
        }, 100)
      })
    },
    methods: {
      setWrapLeft() {
        this.left = -this.width_px * this.tabIndex

        // 这里要注意，没有控制好会影响下面左右滑动的动画流畅度
        if (this.enable_scroll) {
          this.setContLeft(this.left)
        }
      },
      // 控制哪些模块显示，延时设置，优化列表过渡
      // setShow(index) {
      //   let l = this.show_list.length
      //   // this.tabs.forEach((k, i) => {
      //   //   this.show_list[i] = false
      //   // })
      //   setTimeout(() => {
      //     if (index - 3 >= 0) this.show_list[index - 3] = false
      //     if (index - 2 >= 0) this.show_list[index - 2] = true
      //     if (index - 1 >= 0) this.show_list[index - 1] = true
      //     this.show_list[index] = true
      //     if (index + 1 < l) this.show_list[index + 1] = true
      //     if (index + 2 < l) this.show_list[index + 2] = true
      //     if (index + 3 < l) this.show_list[index + 3] = false
      //   }, this.cIndex_time)
      // },
      // 左右拖动
      tchStart(ev) {
        // console.log(1);
        if (!this.enable_scroll) return;
        this.enable_scroll = false

        let This = this
        let tabsContWrap = This.$refs.tabsContWrap

        let tch_time = new Date() // 记录touch时间
        let tch_s = ev.touches[0]
        let tch_start_x = tch_s.clientX // touchstart的X坐标
        let tch_start_y = tch_s.clientY
        let _left = This.left
        let axis = true // touch方向, 在15px内确认。true 为 y轴 false 为 x轴
        let axis_permit = true // 限制每次touch只判断一次
        let max_tabIndex = This.tabs.length - 1 // 最大 tabIndex

        // 关闭过渡效果
        This.setObjCss({
          transitionDuration: '0s',
          transitionProperty: 'none'
        })

        let tchMove = function (ev) {
          let tch_m = ev.touches[0]
          // 确定滑动方向
          if (axis_permit) {
            axis_permit = false
            axis = Math.abs(tch_m.clientX - tch_start_x) <= Math.abs(tch_m.clientY - tch_start_y)
          }
          if (!axis) {
            // ev.stopPropagation()
            ev.preventDefault()

            // 使节点跟随手指移动
            let left = _left + (tch_m.clientX - tch_start_x)
            left = Math.max(left, -max_tabIndex * This.width_px)
            left = Math.min(left, 0)
            This.left = left

            tabsContWrap.style.transform = 'translateX(' + left + 'px)'
          }
        }

        let tchEnd = function (ev) {
          let tch_e_x = ev.changedTouches[0].clientX
          let _tabIndex = This.tabIndex
          let change_x = tch_e_x - tch_start_x // 滑动距离
          let cTime = new Date() - tch_time // 拖动用时
          let velocity = change_x / cTime // 计算滑动速度
          let is_switch = Math.abs(velocity) > 0.4 || Math.abs(change_x) > This.width_px / 3 // 是否切换，使用速度和距离双重判断来判断
          // console.log('velocity', velocity);

          if (!axis && is_switch) {
            // 左 还是 右
            tch_e_x > tch_start_x ? _tabIndex-- : _tabIndex++
            _tabIndex = Math.max(_tabIndex, 0)
            _tabIndex = Math.min(_tabIndex, max_tabIndex)

            if (This.tabIndex === _tabIndex) {
              // tabIndex 没有变化
              This.enable_scroll = true
              This.resetContCss()
            } else {
              // tabIndex 发生变化，使用动画函数达到过渡效果
              This.$emit('tabIndex', _tabIndex) // v-model

              let tLeft = -This.width_px * _tabIndex
              let cLeft = tLeft - This.left
              let time = Math.floor(375 * (Math.abs(cLeft) / This.width_px)) // 过渡动画用时
              time = time - (velocity * 15)
              time = Math.max(time, 10) // time 须大于 10
              // console.log('time', time);
              This.cIndex_time = time

              // 保持滑动惯性过渡 css 版
              This.setObjCss({
                transitionDuration: (time / 1000) + 's',
                transitionProperty: 'transform'
              })
              This.setContLeft(tLeft)
              setTimeout(() => {
                This.enable_scroll = true
                This.resetContCss()
              }, time)
            }
          } else {
            // 没有超过切换值，恢复原样
            This.left = -This.width_px * _tabIndex
            This.enable_scroll = true
            This.resetContCss()
            This.setContLeft(This.left)
          }

          removeEventListener('touchmove', tchMove, {passive: false})
          removeEventListener('touchend', tchEnd, {passive: false})
        }

        addEventListener('touchmove', tchMove, {passive: false})
        addEventListener('touchend', tchEnd, {passive: false})
      },
      // 上拉加载
      // scrollChange(ev) {
      //   if (!this.finished) {
      //     this.emitLoad(ev.target)
      //   }
      // },
      // // 触发load事件，递归重复调用
      // emitLoad(ele) {
      //   // console.log(ele.scrollHeight - ele.scrollTop - this.contHeight, this.offset);
      //   if (ele.scrollHeight - ele.scrollTop - this.contHeight < this.offset && !this.loading) {
      //     this.$emit('loading', true)
      //     this.$emit('load')
      //     setTimeout(() => {
      //       this.emitLoad(ele)
      //     }, 1000)
      //   }
      // },
      // 获取对应长度的px高度
      clientPX(long) {
        let eDiv = document.createElement('div')
        eDiv.style.position = 'absolute'
        eDiv.style.width = long
        eDiv.style.height = '1px'
        document.body.appendChild(eDiv)
        let width = eDiv.clientWidth
        document.body.removeChild(eDiv)
        return width
      },
      // 设置cont偏移量
      setContLeft(left) {
        // this.$refs.tabsContWrap.style.transform = 'translateX(' + left + 'px)'
        this.setObjCss({transform: 'translateX(' + left + 'px)'})
      },
      // 恢复正常样式
      resetContCss() {
        this.setObjCss({
          transitionDuration: '0.375s',
          transitionProperty: 'transform'
        })
      },
      // 设置样式
      setObjCss(css) {
        let tabsContWrap = this.$refs.tabsContWrap
        for (let key in css) {
          tabsContWrap.style[key] = css[key]
        }
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tabs-cont {
    position: relative;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    overflow-x: hidden;
    overflow-y: hidden;
    .tabs-cont-wrap {
      position: absolute;
      top: 0;
      left: 0;
      width: 10000%;
      /*transform-style: preserve-3d;*/
      transform: translate3d(0, 0, 0);
      backface-visibility: hidden;
      perspective: 1000px;

      /*transition-property: transform;*/
      /*transition-delay: 0.05s;*/
      /*transition-duration: 0.3s;*/
      transition-property: transform;
      transition-timing-function: ease-out;
      .tabs-cont-list {

        position: relative;
        float: left;
        width: 375px;
        height: 100%;
        overflow-x: hidden;
        overflow-y: hidden;
      }
    }
    /*.transition {*/
    /*transition-property: none;*/
    /*transition-duration: 0s;*/
    /*}*/
  }
</style>
